#pragma once
#ifndef __HWINOBJ_H__
#define __HWINOBJ_H__

#include "hwinobjbase.h"
#include "hwindatetime.h"


namespace harlinn
{
    namespace windows
    {
        class Persist : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(Persist,Unknown,IPersist,IUnknown)

            CLSID GetClassID( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                CLSID result;
                auto hr = pInterface->GetClassID(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        };

        class PersistStream : public Persist
        {
        public:
            typedef Persist Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(PersistStream,Persist,IPersistStream,IPersist)

            bool IsDirty( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                return pInterface->IsDirty( ) == S_OK?true:false;
            }
        
            PersistStream& Load(IStream *pStm)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Load(pStm);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            PersistStream& Save(IStream *pStm, bool clearDirty)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Save(pStm,clearDirty?TRUE:FALSE);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            unsigned long long GetSizeMax( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULARGE_INTEGER result;
                auto hr = pInterface->GetSizeMax(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result.QuadPart;
            }
        };


        class Moniker;
        class EnumMoniker : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(EnumMoniker,Unknown,IEnumMoniker,IUnknown)

            bool Next( Moniker& theResult );

            bool Next( ULONG requestedNumberOfElements, std::vector<Moniker>& result);
        
            EnumMoniker& Skip(ULONG numberOfElements)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Skip(numberOfElements);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumMoniker& Reset( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Reset();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumMoniker Clone()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumMoniker* pClone = nullptr;
                auto hr = pInterface->Clone(&pClone);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumMoniker(pClone);
            }
        
        };

        class Moniker : public PersistStream
        {
        public:
            typedef PersistStream Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(Moniker,PersistStream,IMoniker,IPersistStream)

            template <typename T>
            T BindToObject( IBindCtx *pbc,IMoniker *pmkToLeft = nullptr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                T::InterfaceType* result;
                auto hr = pInterface->BindToObject(pbc,pmkToLeft,__uuidof(T::InterfaceType),(void**)&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return T(result);
            }
        
            template <typename T>
            T BindToStorage( IBindCtx *pbc,IMoniker *pmkToLeft = nullptr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                T::InterfaceType* result;
                auto hr = pInterface->BindToStorage(pbc,pmkToLeft,__uuidof(T::InterfaceType),(void**)&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return T(result);
            }

            Moniker Reduce(IBindCtx *pbc,DWORD dwReduceHowFar = MKRREDUCE_THROUGHUSER, IMoniker **ppmkToLeft = nullptr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result;
                auto hr = pInterface->Reduce(pbc,dwReduceHowFar,ppmkToLeft,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }
        
            Moniker ComposeWith(IMoniker *pmkRight, bool onlyIfNotGeneric)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result;
                auto hr = pInterface->ComposeWith(pmkRight, onlyIfNotGeneric,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }

            EnumMoniker Enum( bool forward)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumMoniker* result;
                auto hr = pInterface->Enum(forward,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumMoniker(result);
            }
        
            bool IsEqual( IMoniker *otherMoniker )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->IsEqual(otherMoniker);
                if(hr == S_OK)
                {
                    return true;
                }
                else if(hr == S_FALSE)
                {
                    return false;
                }
                else if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return false;
            }
        
            DWORD Hash( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result;
                auto hr = pInterface->Hash(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            bool IsRunning( IBindCtx *pbc, IMoniker *pmkNewlyRunning = nullptr, IMoniker *pmkToLeft = nullptr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->IsRunning(pbc, pmkToLeft, pmkNewlyRunning);
                if(hr == S_OK)
                {
                    return true;
                }
                else if(hr == S_FALSE)
                {
                    return false;
                }
                else if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return false;
            }
        
            DateTime GetTimeOfLastChange( IBindCtx *pbc, IMoniker *pmkToLeft = nullptr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                FILETIME result;
                auto hr = pInterface->GetTimeOfLastChange(pbc, pmkToLeft,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return DateTime::FromFileTimeUtc(*(long long*)&result);
            }
        
            Moniker Inverse( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result;
                auto hr = pInterface->Inverse(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }
            Moniker CommonPrefixWith( IMoniker *pmkOther )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result;
                auto hr = pInterface->CommonPrefixWith( pmkOther,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }

            Moniker RelativePathTo( IMoniker *pmkOther )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result;
                auto hr = pInterface->RelativePathTo( pmkOther,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }
            String GetDisplayName( IBindCtx *pbc, IMoniker *pmkToLeft = nullptr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                Malloc malloc = Malloc::GetMalloc();
                LPOLESTR result = nullptr;
                auto hr = pInterface->GetDisplayName( pbc, pmkToLeft, &result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                String s(result);
                malloc.Free(result);
                return s;
            }
            Moniker ParseDisplayName( IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result;
                auto hr = pInterface->ParseDisplayName( pbc, pmkToLeft, pszDisplayName, pchEaten,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }
            MKSYS IsSystemMoniker( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->IsSystemMoniker(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return MKSYS(result);
            }
        
        };


        inline bool EnumMoniker::Next( Moniker& theResult )
        {
            HWIN_TRACE();
            auto pInterface = GetInterface();
            IMoniker* pElement = nullptr;
            ULONG actual = 0;
            auto hr = pInterface->Next(1,&pElement,&actual);
            if(actual)
            {
                theResult.Reset(pElement);
                return true;
            }
            return false;
        }

        inline bool EnumMoniker::Next( ULONG requestedNumberOfElements, std::vector<Moniker>& result)
        {
            HWIN_TRACE();
            auto pInterface = GetInterface();
            IMoniker** pElements = (IMoniker**)alloca(requestedNumberOfElements*sizeof(IMoniker*));
            memset(pElements,0,requestedNumberOfElements*sizeof(IMoniker*));
            ULONG actual = 0;

            auto hr = pInterface->Next(1,pElements,&actual);
            if(actual)
            {
                result.clear();
                for(ULONG i= 0; i < actual; i++)
                {
                    result.push_back(Moniker(pElements[i]));
                }
                return true;
            }
            return false;
        }


        class RunningObjectTable : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(RunningObjectTable,Unknown,IRunningObjectTable,IUnknown)

            DWORD Register(DWORD flags, IUnknown *object, IMoniker *objectName)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->Register(flags, object, objectName, &result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

            RunningObjectTable& Revoke(DWORD dwRegister)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->Revoke(dwRegister);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            bool IsRunning(IMoniker *objectName)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->IsRunning(objectName);
                if(hr == S_OK)
                {
                    return true;
                }
                else if(hr == S_FALSE)
                {
                    return false;
                }
                else if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return false;
            }

            Unknown GetObject( IMoniker *pmkObjectName)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IUnknown* result = 0;
                auto hr = pInterface->GetObject(pmkObjectName,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Unknown(result);
            }
        
            RunningObjectTable& NoteChangeTime(DWORD dwRegister, const DateTime& time)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                long long filetime = time.ToFileTimeUtc();
                auto hr = pInterface->NoteChangeTime(dwRegister, ((FILETIME*)&filetime));
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            DateTime GetTimeOfLastChange(IMoniker *pmkObjectName)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                FILETIME result;
                auto hr = pInterface->GetTimeOfLastChange(pmkObjectName,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return DateTime::FromFileTimeUtc(*(long long*)&result);
            }
        
            EnumMoniker EnumRunning( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumMoniker* result = 0;
                auto hr = pInterface->EnumRunning(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumMoniker(result);
            }
        
        };


        class BindCtx : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(BindCtx,Unknown,IBindCtx,IUnknown)


            static BindCtx Create()
            {
                HWIN_TRACE();
                IBindCtx* result = nullptr;
                auto hr = CreateBindCtx(0,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return BindCtx(result);
            }

            BindCtx& RegisterObjectBound(IUnknown *punk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->RegisterObjectBound(punk);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            BindCtx& RevokeObjectBound(IUnknown *punk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->RevokeObjectBound(punk);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            BindCtx& ReleaseBoundObjects( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ReleaseBoundObjects( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            BindCtx& SetBindOptions( BIND_OPTS *pbindopts)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetBindOptions( pbindopts );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            BindCtx& GetBindOptions( BIND_OPTS *pbindopts)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetBindOptions( pbindopts );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            RunningObjectTable GetRunningObjectTable( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IRunningObjectTable* result = 0;
                auto hr = pInterface->GetRunningObjectTable(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return RunningObjectTable(result);
            }

            BindCtx& RegisterObjectParam(LPOLESTR pszKey,IUnknown *punk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->RegisterObjectParam(pszKey,punk);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            Unknown GetObjectParam( LPOLESTR pszKey )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IUnknown* result = 0;
                auto hr = pInterface->GetObjectParam(pszKey, &result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Unknown(result);
            }

            EnumString EnumObjectParam( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumString* result = 0;
                auto hr = pInterface->EnumObjectParam(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumString(result);
            }
        
            BindCtx& RevokeObjectParam( LPOLESTR pszKey )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->RevokeObjectParam(pszKey);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
        };


        class RunnableObject : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(RunnableObject,Unknown,IRunnableObject,IUnknown)

            CLSID GetRunningClass( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                CLSID result;
                auto hr = pInterface->GetRunningClass(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
            
        
            RunnableObject& Run(LPBINDCTX pbc)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Run(pbc);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            bool IsRunning(void)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->IsRunning( );
                if(hr == TRUE)
                {
                    return true;
                }
                return false;
            }
        
            RunnableObject& LockRunning( bool lock, bool lastUnlockCloses)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->LockRunning( lock, lastUnlockCloses );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            RunnableObject& SetContainedObject(bool contained)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetContainedObject(contained);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };


        class ROTData : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ROTData,Unknown,IROTData,IUnknown)

            std::vector<BYTE> GetComparisonData( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                BYTE buffer[2048];
                ULONG actual = 0;
                auto hr = pInterface->GetComparisonData(buffer,2048,&actual);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                std::vector<BYTE> result(buffer,buffer+actual);
                return result;
            }
        };


        class EnumSTATSTG : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(EnumSTATSTG,Unknown,IEnumSTATSTG,IUnknown)

            bool Next( STATSTG& theResult )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IUnknown* pElement = nullptr;
                ULONG actual = 0;
                auto hr = pInterface->Next(1,&theResult,&actual);
                if(actual)
                {
                    return true;
                }
                return false;
            }

            bool Next( ULONG requestedNumberOfElements, std::vector<STATSTG>& result)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                STATSTG* pElements = (STATSTG*)alloca(requestedNumberOfElements*sizeof(STATSTG));
                memset(pElements,0,requestedNumberOfElements*sizeof(STATSTG));
                ULONG actual = 0;

                auto hr = pInterface->Next(1,pElements,&actual);
                if(actual)
                {
                    result.clear();
                    for(ULONG i= 0; i < actual; i++)
                    {
                        result.push_back(pElements[i]);
                    }
                    return true;
                }
                return false;
            }

            EnumSTATSTG& Skip(ULONG numberOfElements)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Skip(numberOfElements);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumSTATSTG& Reset( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Reset();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumSTATSTG Clone()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumSTATSTG* pClone = nullptr;
                auto hr = pInterface->Clone(&pClone);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumSTATSTG(pClone);
            }
        
        };


        class Storage : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(Storage,Unknown,IStorage,IUnknown)

            Stream CreateStream(const OLECHAR *pwcsName, DWORD grfMode)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IStream* pResult = nullptr;
                auto hr = pInterface->CreateStream(pwcsName,grfMode,0,0,&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Stream(pResult);
            }

            Stream OpenStream(const OLECHAR *pwcsName,DWORD grfMode)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IStream* pResult = nullptr;
                auto hr = pInterface->OpenStream(pwcsName,0,grfMode,0,&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Stream(pResult);
            }
        
            Storage CreateStorage( const OLECHAR *pwcsName, DWORD grfMode)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IStorage* pResult = nullptr;
                auto hr = pInterface->CreateStorage(pwcsName,grfMode,0,0,&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Storage(pResult);
            }
        
            Storage OpenStorage(const OLECHAR *pwcsName,DWORD grfMode)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IStorage* pResult = nullptr;
                auto hr = pInterface->OpenStorage(pwcsName,nullptr,grfMode,nullptr,0,&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Storage(pResult);
            }
        
            Storage& CopyTo( DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            Storage& MoveElementTo( const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags = STGMOVE_MOVE)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->MoveElementTo( pwcsName, pstgDest, pwcsNewName, grfFlags);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            Storage& Commit( DWORD grfCommitFlags)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Commit( grfCommitFlags );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            Storage& Revert( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Revert( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumSTATSTG EnumElements( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumSTATSTG* pResult = nullptr;
                auto hr = pInterface->EnumElements(0,0,0,&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumSTATSTG(pResult);
            }
        
            Storage& DestroyElement(const OLECHAR *pwcsName)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->DestroyElement( pwcsName );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            Storage& RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->RenameElement(pwcsOldName, pwcsNewName );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            Storage& SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetElementTimes(pwcsName, pctime, patime, pmtime);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            Storage& SetClass(REFCLSID clsid)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetClass(clsid);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            Storage& SetStateBits(DWORD grfStateBits, DWORD grfMask)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetStateBits(grfStateBits, grfMask);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            Storage& Stat(STATSTG *pstatstg, DWORD grfStatFlag)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Stat(pstatstg, grfStatFlag);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            Storage& WriteClassId(REFCLSID rclsid)
            {
                HWIN_TRACE();
                auto hr = WriteClassStg(*this,rclsid);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }


            CLSID ReadClassId( )
            {
                HWIN_TRACE();
                CLSID result = {0,};
                auto hr = ReadClassStg(*this,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                result;
            }
        
        };


        class PersistFile : public Persist
        {
        public:
            typedef Persist Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(PersistFile,Persist,IPersistFile,IPersist)

            bool IsDirty( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->IsDirty( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                if(hr == S_OK)
                {
                    return true;
                }
                else if(hr == S_FALSE)
                {
                    return false;
                }
                else if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return false;
            }
        
            PersistFile& Load( LPCOLESTR pszFileName, DWORD mode = 0)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Load( pszFileName, mode);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
            PersistFile& Save( LPCOLESTR pszFileName, BOOL remember)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Load( pszFileName, remember);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            PersistFile& SaveCompleted(LPCOLESTR pszFileName)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SaveCompleted( pszFileName );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            bool GetCurFile( String& theFilename )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                Malloc malloc = Malloc::GetMalloc();
                LPOLESTR result = nullptr;
                auto hr = pInterface->GetCurFile(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                String s(result);
                malloc.Free(result);
                theFilename = s;
                return hr == S_OK;
            }
        };


        class PersistStorage : public Persist
        {
        public:
            typedef Persist Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(PersistStorage,Persist,IPersistStorage,IPersist)

            bool IsDirty( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->IsDirty( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                if(hr == S_OK)
                {
                    return true;
                }
                else if(hr == S_FALSE)
                {
                    return false;
                }
                else if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return false;
            }
        
            PersistStorage& InitNew(IStorage *pStg)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->InitNew( pStg );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
            PersistStorage& Load(IStorage *pStg)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Load( pStg );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            PersistStorage& Save(IStorage *pStgSave, bool sameAsLoad)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Save( pStgSave, sameAsLoad );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            PersistStorage& SaveCompleted(IStorage *pStgNew)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SaveCompleted( pStgNew );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            PersistStorage& HandsOffStorage( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->HandsOffStorage( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };


        class LockBytes : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(LockBytes,Unknown,ILockBytes,IUnknown)

            ULONG ReadAt(unsigned long long ulOffset, void *pv,ULONG cb)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->ReadAt(*((ULARGE_INTEGER*)&ulOffset), pv,cb,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            ULONG WriteAt( unsigned long long ulOffset,const void *pv,ULONG cb)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->WriteAt(*((ULARGE_INTEGER*)&ulOffset), pv,cb,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            LockBytes& Flush( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->Flush( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            LockBytes& SetSize( unsigned long long cb)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->SetSize(*((ULARGE_INTEGER*)&cb) );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            LockBytes& LockRegion( unsigned long long libOffset, unsigned long long cb, DWORD dwLockType)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->LockRegion( *((ULARGE_INTEGER*)&libOffset), *((ULARGE_INTEGER*)&cb), dwLockType);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            LockBytes& UnlockRegion( unsigned long long libOffset, unsigned long long cb, DWORD dwLockType)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->UnlockRegion( *((ULARGE_INTEGER*)&libOffset), *((ULARGE_INTEGER*)&cb), dwLockType);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            LockBytes& Stat( STATSTG *pstatstg, DWORD grfStatFlag)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->Stat( pstatstg, grfStatFlag);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
        };


        class EnumFORMATETC : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(EnumFORMATETC,Unknown,IEnumFORMATETC,IUnknown)


            static EnumFORMATETC Create(const std::vector<FORMATETC>& elements)
            {
                HWIN_TRACE();
                UINT numberOfElements = UINT(elements.size());
                const FORMATETC* data = elements.data();
                IEnumFORMATETC* pResult; 

                auto hr = CreateFormatEnumerator(numberOfElements,const_cast<FORMATETC*>(data),&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumFORMATETC(pResult);
            }

            static EnumFORMATETC Create(const FORMATETC* elements, UINT numberOfElements)
            {
                HWIN_TRACE();
                IEnumFORMATETC* pResult; 

                auto hr = CreateFormatEnumerator(numberOfElements,const_cast<FORMATETC*>(elements),&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumFORMATETC(pResult);
            }


            bool Next( FORMATETC& theResult )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IUnknown* pElement = nullptr;
                ULONG actual = 0;
                auto hr = pInterface->Next(1,&theResult,&actual);
                if(actual)
                {
                    return true;
                }
                return false;
            }
            bool Next( ULONG requestedNumberOfElements, std::vector<FORMATETC>& result)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                FORMATETC* pElements = (FORMATETC*)alloca(requestedNumberOfElements*sizeof(FORMATETC));
                memset(pElements,0,requestedNumberOfElements*sizeof(FORMATETC));
                ULONG actual = 0;

                auto hr = pInterface->Next(1,pElements,&actual);
                if(actual)
                {
                    result.clear();
                    for(ULONG i= 0; i < actual; i++)
                    {
                        result.push_back(pElements[i]);
                    }
                    return true;
                }
                return false;
            }
            EnumFORMATETC& Skip(ULONG numberOfElements)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Skip(numberOfElements);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumFORMATETC& Reset( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Reset();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumFORMATETC Clone()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumFORMATETC* pClone = nullptr;
                auto hr = pInterface->Clone(&pClone);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumFORMATETC(pClone);
            }
        
        };


        class EnumSTATDATA : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(EnumSTATDATA,Unknown,IEnumSTATDATA,IUnknown)

            bool Next( STATDATA& theResult )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IUnknown* pElement = nullptr;
                ULONG actual = 0;
                auto hr = pInterface->Next(1,&theResult,&actual);
                if(actual)
                {
                    return true;
                }
                return false;
            }
            bool Next( ULONG requestedNumberOfElements, std::vector<STATDATA>& result)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                STATDATA* pElements = (STATDATA*)alloca(requestedNumberOfElements*sizeof(STATDATA));
                memset(pElements,0,requestedNumberOfElements*sizeof(STATDATA));
                ULONG actual = 0;

                auto hr = pInterface->Next(1,pElements,&actual);
                if(actual)
                {
                    result.clear();
                    for(ULONG i= 0; i < actual; i++)
                    {
                        result.push_back(pElements[i]);
                    }
                    return true;
                }
                return false;
            }
            EnumSTATDATA& Skip(ULONG numberOfElements)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Skip(numberOfElements);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumSTATDATA& Reset( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Reset();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumSTATDATA Clone()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumSTATDATA* pClone = nullptr;
                auto hr = pInterface->Clone(&pClone);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumSTATDATA(pClone);
            }
        
        };


        class RootStorage : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(RootStorage,Unknown,IRootStorage,IUnknown)

            RootStorage& SwitchToFile(LPOLESTR pszFile)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SwitchToFile(pszFile);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };

        class AdviseSink : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(AdviseSink,Unknown,IAdviseSink,IUnknown)

            AdviseSink& OnDataChange( FORMATETC *pFormatetc, STGMEDIUM *pStgmed)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->OnDataChange( pFormatetc, pStgmed);
                return *this;
            }
        
            AdviseSink& OnViewChange( DWORD dwAspect, LONG lindex)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->OnViewChange( dwAspect, lindex);
                return *this;
            }
            AdviseSink& OnRename( IMoniker *pmk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->OnRename( pmk );
                return *this;
            }
            AdviseSink& OnSave( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->OnSave( );
                return *this;
            }
            AdviseSink& OnClose( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->OnClose( );
                return *this;
            }
        };

        class AsyncAdviseSink : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(AsyncAdviseSink,Unknown,AsyncIAdviseSink,IUnknown)

            AsyncAdviseSink& Begin_OnDataChange( FORMATETC *pFormatetc, STGMEDIUM *pStgmed)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Begin_OnDataChange( pFormatetc, pStgmed);
                return *this;
            }
            AsyncAdviseSink& Finish_OnDataChange( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Finish_OnDataChange( );
                return *this;
            }
            AsyncAdviseSink& Begin_OnViewChange( DWORD dwAspect, LONG lindex)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Begin_OnViewChange( dwAspect, lindex);
                return *this;
            }
            AsyncAdviseSink& Finish_OnViewChange( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Finish_OnViewChange( );
                return *this;
            }
            AsyncAdviseSink& Begin_OnRename(IMoniker *pmk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Begin_OnRename( pmk);
                return *this;
            }
            AsyncAdviseSink& Finish_OnRename( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Finish_OnRename( );
                return *this;
            }
            AsyncAdviseSink& Begin_OnSave( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Begin_OnSave( );
                return *this;
            }
            AsyncAdviseSink& Finish_OnSave( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Finish_OnSave( );
                return *this;
            }
            AsyncAdviseSink& Begin_OnClose( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Begin_OnClose( );
                return *this;
            }
            AsyncAdviseSink& Finish_OnClose( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Finish_OnClose( );
                return *this;
            }
        };


        class AdviseSink2 : public AdviseSink
        {
        public:
            typedef AdviseSink Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(AdviseSink2,AdviseSink,IAdviseSink2,IAdviseSink)

            AdviseSink2& OnLinkSrcChange(IMoniker *pmk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->OnLinkSrcChange( pmk );
                return *this;
            }
        
        };


        class AsyncAdviseSink2 : public AsyncAdviseSink
        {
        public:
            typedef AsyncAdviseSink Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(AsyncAdviseSink2,AsyncAdviseSink,AsyncIAdviseSink2,AsyncIAdviseSink)

            AsyncAdviseSink2& Begin_OnLinkSrcChange(IMoniker *pmk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Begin_OnLinkSrcChange(pmk);
                return *this;
            }
        
            AsyncAdviseSink2& Finish_OnLinkSrcChange( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->Finish_OnLinkSrcChange();
                return *this;
            }
        
        };

        class StgMedium
        {
            STGMEDIUM* data;

            StgMedium(const StgMedium& other)
                : data(0)
            {
                HWIN_TRACE();
            }

            StgMedium& operator = (const StgMedium& other)
            {
                HWIN_TRACE();
            }
        public:

            StgMedium(bool allocate = false)
                : data(0)
            {
                HWIN_TRACE();
                if(allocate)
                {
                    data = new STGMEDIUM;
                    memset(data,0,sizeof(STGMEDIUM));
                }
            }

            StgMedium(StgMedium&& other)
                : data(other.data)
            {
                HWIN_TRACE();
                other.data = nullptr;
            }

            explicit StgMedium(STGMEDIUM* theData)
                : data(theData)
            {
                HWIN_TRACE();
            }

            ~StgMedium()
            {
                HWIN_TRACE();
                if(data)
                {
                    ReleaseStgMedium(data); 
                }
            }

            StgMedium& operator = (StgMedium&& other)
            {
                HWIN_TRACE();
                data = other.data;
                other.data = nullptr;
            }

            StgMedium& operator = (STGMEDIUM* theData)
            {
                HWIN_TRACE();
                if(theData != data)
                {
                    if(data)
                    {
                        ReleaseStgMedium(data);
                        delete data;
                        data = nullptr;
                    }
                    data = theData;
                }
            }

            STGMEDIUM* Data() const 
            { 
                HWIN_TRACE();
                return data; 
            }
            STGMEDIUM* get() const 
            { 
                HWIN_TRACE();
                return data; 
            }

        };


        enum class DropEffect : DWORD
        {
            None = DROPEFFECT_NONE,
            Copy = DROPEFFECT_COPY,
            Move = DROPEFFECT_MOVE,
            Link = DROPEFFECT_LINK,
            Scroll = DROPEFFECT_SCROLL
        };
        DEFINE_ENUM_FLAG_OPERATORS(DropEffect)


        class DataObject : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(DataObject,Unknown,IDataObject,IUnknown)


            DropEffect DoDragDrop(LPDROPSOURCE pDropSource, DropEffect dropEffect = DropEffect::Copy | DropEffect::Move | DropEffect::Link)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                
                DWORD result = 0;
                DWORD dwOKEffects = DWORD(dropEffect);
                auto hr = ::DoDragDrop(pInterface, pDropSource, dwOKEffects, &result);
                
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }

                return DropEffect(result);
            }

            StgMedium GetData( FORMATETC *pformatetcIn )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                StgMedium medium(true);
                auto hr = pInterface->GetData(pformatetcIn,medium.Data());
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return medium;
            }
            StgMedium GetDataHere( FORMATETC *pformatetc)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                StgMedium medium(true);
                auto hr = pInterface->GetDataHere(pformatetc,medium.Data());
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return medium;
            }
            bool QueryGetData(FORMATETC *pformatetc)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->QueryGetData(pformatetc);
                return hr == S_OK;
            }

            // returns false if DATA_S_SAMEFORMATETC
            bool GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetCanonicalFormatEtc(pformatectIn, pformatetcOut);
                if(hr == S_OK)
                {
                    return true;
                }
                else if(hr == DATA_S_SAMEFORMATETC)
                {
                    return false;
                }
                if(FAILED(hr))
                {
                    // anything else should cause the CheckHRESULT to throw an
                    // exception
                    CheckHRESULT(hr); 
                }
                return false;
            }

            DataObject& SetData( FORMATETC *pformatetc,STGMEDIUM *pmedium,BOOL fRelease)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetData( pformatetc,pmedium,fRelease);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr); 
                }
                return *this;
            }

            EnumFORMATETC EnumFormatEtc( DWORD dwDirection)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumFORMATETC* pEnum = nullptr;
                auto hr = pInterface->EnumFormatEtc(dwDirection,&pEnum);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumFORMATETC(pEnum);
            }

            DWORD DAdvise( FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->DAdvise( pformatetc, advf, pAdvSink, &result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

            DataObject& DUnadvise( DWORD dwConnection)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->DUnadvise(dwConnection);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr); 
                }
                return *this;
            }

            EnumSTATDATA EnumDAdvise( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumSTATDATA* pEnum = nullptr;
                auto hr = pInterface->EnumDAdvise(&pEnum);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumSTATDATA(pEnum);
            }
        };


        class DataAdviseHolder : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(DataAdviseHolder,Unknown,IDataAdviseHolder,IUnknown)

            static DataAdviseHolder Create()
            {
                HWIN_TRACE();
                
                IDataAdviseHolder* pResult = nullptr;
                auto hr = CreateDataAdviseHolder(&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return DataAdviseHolder(pResult);
            }

            DWORD Advise( IDataObject *pDataObject,FORMATETC *pFetc, DWORD advf, IAdviseSink *pAdvise)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->Advise( pDataObject,pFetc, advf, pAdvise, &result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

            DataAdviseHolder& Unadvise(DWORD dwConnection)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Unadvise(dwConnection);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr); 
                }
                return *this;
            }

            EnumSTATDATA EnumAdvise( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumSTATDATA* pEnum = nullptr;
                auto hr = pInterface->EnumAdvise(&pEnum);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumSTATDATA(pEnum);
            }
        
            DataAdviseHolder& SendOnDataChange( IDataObject *pDataObject,DWORD advf)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SendOnDataChange( pDataObject,0,advf);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr); 
                }
                return *this;
            }
        
        };


        class MessageFilter : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(MessageFilter,Unknown,IMessageFilter,IUnknown)

            DWORD HandleInComingCall(DWORD dwCallType,HTASK htaskCaller,DWORD dwTickCount, LPINTERFACEINFO lpInterfaceInfo)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto result = pInterface->HandleInComingCall(dwCallType,htaskCaller,dwTickCount, lpInterfaceInfo);
                return result;
            }
        
            DWORD RetryRejectedCall( HTASK htaskCallee,DWORD dwTickCount,DWORD dwRejectType)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto result = pInterface->RetryRejectedCall( htaskCallee,dwTickCount,dwRejectType);
                return result;
            }
        
            DWORD MessagePending( HTASK htaskCallee,DWORD dwTickCount,DWORD dwPendingType)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto result = pInterface->MessagePending( htaskCallee,dwTickCount,dwPendingType);
                return result;
            }
        };

        class ClassActivator : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ClassActivator,Unknown,IClassActivator,IUnknown)

            template<typename T>
            T GetClassObject( REFCLSID rclsid, DWORD dwClassContext, LCID locale)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                T::InterfaceType* pRequestedInterface = nullptr;
                auto result = pInterface->GetClassObject( REFCLSID rclsid, DWORD dwClassContext, LCID locale,__uuidof(T::InterfaceType),(void**)&pRequestedInterface);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr); 
                }
                return T(pRequestedInterface);
            }
        };


        class FillLockBytes : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(FillLockBytes,Unknown,IFillLockBytes,IUnknown)

            ULONG FillAppend( const void *pv,ULONG cb)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->FillAppend( pv,cb,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            ULONG FillAt( unsigned long long ulOffset, const void *pv, ULONG cb)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG result = 0;
                auto hr = pInterface->FillAt( *((ULARGE_INTEGER*)&ulOffset),pv,cb,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            FillLockBytes& SetFillSize(unsigned long long ulSize)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetFillSize( *((ULARGE_INTEGER*)&ulSize));
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            FillLockBytes& Terminate(bool bCanceled)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Terminate(bCanceled);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

        };


        class ProgressNotify : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ProgressNotify,Unknown,IProgressNotify,IUnknown)

            DWORD OnProgress( DWORD dwProgressCurrent,DWORD dwProgressMaximum,bool fAccurate,bool fOwner)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->OnProgress( dwProgressCurrent,dwProgressMaximum,fAccurate,fOwner);
                if((hr != E_PENDING)&&
                    (hr != STG_S_RETRYNOW)&&
                    (hr != STG_S_BLOCK)&&
                    (hr != STG_S_MONITORING)&&
                    (FAILED(hr)))
                {
                    CheckHRESULT(hr);
                }
                return hr;
            }
        };


        class LayoutStorage : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(LayoutStorage,Unknown,ILayoutStorage,IUnknown)

            LayoutStorage& LayoutScript( StorageLayout *pStorageLayout, DWORD nEntries)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->LayoutScript( pStorageLayout, nEntries,0);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            LayoutStorage& BeginMonitor( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->BeginMonitor( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            LayoutStorage& EndMonitor( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->EndMonitor( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            LayoutStorage& ReLayoutDocfile(OLECHAR *pwcsNewDfName)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ReLayoutDocfile(pwcsNewDfName);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            LayoutStorage& ReLayoutDocfileOnILockBytes(ILockBytes *pILockBytes)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ReLayoutDocfileOnILockBytes(pILockBytes);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };

        class BlockingLock : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(BlockingLock,Unknown,IBlockingLock,IUnknown)

            BlockingLock& Lock(DWORD timeout)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Lock(timeout);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
            BlockingLock& Lock(const TimeSpan& timeout)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD to = (DWORD)timeout.TotalMilliseconds();
                auto hr = pInterface->Lock(to);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            BlockingLock& Unlock( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Unlock();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };


        class DirectWriterLock : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(DirectWriterLock,Unknown,IDirectWriterLock,IUnknown)

            DirectWriterLock& WaitForWriteAccess( DWORD dwTimeout )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->WaitForWriteAccess(dwTimeout);
                if(hr == STG_E_INUSE)
                {
                    throw new TimeoutException("Timeout in "__FUNCTION__);
                }
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            DirectWriterLock& ReleaseWriteAccess( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ReleaseWriteAccess();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            bool HaveWriteAccess( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->HaveWriteAccess( );
                if(hr == S_OK)
                {
                    return true;
                }
                else if(hr == S_FALSE)
                {
                    return false;
                }
                else if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return false;
            }
        };


        class ForegroundTransfer : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ForegroundTransfer,Unknown,IForegroundTransfer,IUnknown)

            ForegroundTransfer& AllowForegroundTransfer( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->AllowForegroundTransfer(nullptr);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };

        class ProcessLock : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ProcessLock,Unknown,IProcessLock,IUnknown)

            ULONG AddRefOnProcess( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto result = pInterface->AddRefOnProcess( );
                return result;
            }
        
            ULONG ReleaseRefOnProcess( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto result = pInterface->ReleaseRefOnProcess( );
                return result;
            }
        };

        class SurrogateService : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(SurrogateService,Unknown,ISurrogateService,IUnknown)

            bool Init( REFGUID rguidProcessID, IProcessLock *pProcessLock)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                BOOL applicationAware = FALSE;
                auto hr = pInterface->Init( rguidProcessID, pProcessLock,&applicationAware);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return applicationAware != FALSE;
            }

            SurrogateService& ApplicationLaunch( REFGUID rguidApplID, ApplicationType appType)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ApplicationLaunch( rguidApplID, appType);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
            SurrogateService& ApplicationFree(REFGUID rguidApplID)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ApplicationFree(rguidApplID);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            SurrogateService& CatalogRefresh( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->CatalogRefresh(0);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            SurrogateService& ProcessShutdown( ShutdownType shutdownType)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ProcessShutdown(shutdownType);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
        };



        class TypeComp : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(TypeComp,Unknown,ITypeComp,IUnknown)

            TypeComp& Bind( LPOLESTR szName,ULONG lHashVal,WORD wFlags, ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Bind( szName,lHashVal,wFlags, ppTInfo, pDescKind, pBindPtr);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            TypeComp& BindType( LPOLESTR szName,ULONG lHashVal,ITypeInfo **ppTInfo,ITypeComp **ppTComp)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->BindType( szName,lHashVal,ppTInfo,ppTComp);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };


        

        class TypeLib;
        class TypeInfo : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(TypeInfo,Unknown,ITypeInfo,IUnknown)

            TypeInfo& GetTypeAttr( TYPEATTR **ppTypeAttr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetTypeAttr( ppTypeAttr);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            TypeComp GetTypeComp( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ITypeComp* result = nullptr; 
                auto hr = pInterface->GetTypeComp( &result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return TypeComp(result);
            }
        
            TypeInfo& GetFuncDesc( UINT index,FUNCDESC **ppFuncDesc)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetFuncDesc( index,ppFuncDesc );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            TypeInfo& GetVarDesc( UINT index,VARDESC **ppVarDesc)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetVarDesc( index,ppVarDesc );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            TypeInfo& GetNames( MEMBERID memid, BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetNames( memid, rgBstrNames, cMaxNames, pcNames);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            TypeInfo& GetRefTypeOfImplType( UINT index,HREFTYPE *pRefType)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetRefTypeOfImplType( index,pRefType);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            INT GetImplTypeFlags( UINT index )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                int result = 0;
                auto hr = pInterface->GetImplTypeFlags( index,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            TypeInfo& GetIDsOfNames( LPOLESTR *rgszNames, UINT cNames, MEMBERID *pMemId)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetIDsOfNames( rgszNames, cNames, pMemId);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            HRESULT Invoke( PVOID pvInstance,MEMBERID memid,WORD wFlags,DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Invoke( pvInstance,memid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
                return hr;
            }
        
            TypeInfo& GetDocumentation( MEMBERID memid, SysString& theName, SysString& theDocString, DWORD& pdwHelpContext, SysString& theHelpFile)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                BSTR bstrName;
                BSTR bstrDocString;
                BSTR bstrHelpFile;
                auto hr = pInterface->GetDocumentation( memid, &bstrName, &bstrDocString, &pdwHelpContext, &bstrHelpFile);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                theName.Attach( bstrName );
                theDocString.Attach( bstrDocString );
                theHelpFile.Attach( bstrHelpFile );
                return *this;
            }
        
            TypeInfo& GetDllEntry( MEMBERID memid,INVOKEKIND invKind,SysString& theDllName,SysString& theName,WORD& pwOrdinal)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                BSTR bstrName;
                BSTR bstrDllName;
                auto hr = pInterface->GetDllEntry( memid,invKind,&bstrDllName,&bstrName,&pwOrdinal);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                theName.Attach( bstrName );
                theDllName.Attach( bstrDllName );
                return *this;
            }
        
            TypeInfo GetRefTypeInfo( HREFTYPE hRefType )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ITypeInfo* result;
                auto hr = pInterface->GetRefTypeInfo( hRefType,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return TypeInfo(result);
            }
        
            TypeInfo& AddressOfMember( MEMBERID memid,INVOKEKIND invKind,PVOID *ppv)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->AddressOfMember( memid,invKind,ppv);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            TypeInfo& CreateInstance(IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->CreateInstance(pUnkOuter, riid, ppvObj);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            template<typename T>
            T CreateInstance(REFIID riid,IUnknown *pUnkOuter = nullptr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IUnknown* pUnknown = nullptr;
                auto hr = pInterface->CreateInstance(pUnkOuter, riid, (void**)&pUnknown);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }

                T::InterfaceType* result;
                hr = pUnknown->QueryInterface(__uuidof(T::InterfaceType),(void**)&result);
                pUnknown->Release();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }

                return T(result);
            }


            TypeInfo& GetMops( MEMBERID memid, BSTR *pBstrMops)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetMops( memid, pBstrMops);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            TypeLib GetContainingTypeLib(UINT& pIndex);
        
            TypeInfo& ReleaseTypeAttr(TYPEATTR *pTypeAttr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->ReleaseTypeAttr(pTypeAttr);
                return *this;
            }
        
            TypeInfo& ReleaseFuncDesc( FUNCDESC *pFuncDesc )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->ReleaseFuncDesc(pFuncDesc);
                return *this;
            }
            TypeInfo& ReleaseVarDesc( VARDESC *pVarDesc)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->ReleaseVarDesc( pVarDesc);
                return *this;
            }
        };
        
        class TypeLib : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(TypeLib,Unknown,ITypeLib,IUnknown)

            UINT GetTypeInfoCount( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto result = pInterface->GetTypeInfoCount( );
                return result;
            }
        
            TypeInfo GetTypeInfo( UINT index )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ITypeInfo* result;
                auto hr = pInterface->GetTypeInfo(index,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return TypeInfo(result);
            }
        
            TYPEKIND GetTypeInfoType( UINT index )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                TYPEKIND result;
                auto hr = pInterface->GetTypeInfoType(index,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            TypeInfo GetTypeInfoOfGuid( REFGUID guid )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ITypeInfo* result;
                auto hr = pInterface->GetTypeInfoOfGuid(guid,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return TypeInfo(result);
            }
        
            TypeLib& GetLibAttr(TLIBATTR **ppTLibAttr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetLibAttr(ppTLibAttr);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            TypeComp GetTypeComp( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ITypeComp* result;
                auto hr = pInterface->GetTypeComp(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return TypeComp(result);
            }

            TypeLib& GetDocumentation( INT index,BSTR *pBstrName,BSTR *pBstrDocString,DWORD *pdwHelpContext, BSTR *pBstrHelpFile)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetDocumentation( index,pBstrName,pBstrDocString,pdwHelpContext, pBstrHelpFile);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            bool IsName( LPOLESTR szNameBuf,ULONG lHashVal )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                BOOL result = FALSE;
                auto hr = pInterface->IsName( szNameBuf,lHashVal,&result );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result != FALSE;
            }
        
            TypeLib& FindName( LPOLESTR szNameBuf,ULONG lHashVal, ITypeInfo **ppTInfo, MEMBERID *rgMemId,USHORT *pcFound)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->FindName( szNameBuf,lHashVal, ppTInfo, rgMemId,pcFound);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            TypeLib& ReleaseTLibAttr(TLIBATTR *pTLibAttr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                pInterface->ReleaseTLibAttr(pTLibAttr);
                return *this;
            }

        };


        class Dispatch : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(Dispatch,Unknown,IDispatch,IUnknown)


            UINT GetTypeInfoCount()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                UINT result = 0;
                auto hr = pInterface->GetTypeInfoCount(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

            TypeInfo GetTypeInfo( UINT iTInfo, LCID lcid = LOCALE_SYSTEM_DEFAULT)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ITypeInfo* result;
                auto hr = pInterface->GetTypeInfo(iTInfo, lcid,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return TypeInfo(result);
            }
        
            Dispatch& GetIDsOfNames( LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->GetIDsOfNames( IID_NULL,rgszNames, cNames, lcid, rgDispId);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }


            std::shared_ptr< std::vector< DISPID > > GetIDsOfNames( const std::shared_ptr< std::vector <String> > names,  LCID lcid = LOCALE_SYSTEM_DEFAULT)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                std::shared_ptr< std::vector< DISPID > > result = std::make_shared< std::vector< DISPID > >(  names->size() );

                std::vector< const wchar_t* > nms;
                nms.reserve(names->size());

                for( auto it = names->begin(); it != names->end(); it++ )
                {
                    const String& s = *it;
                    const wchar_t* ptr = s.c_str();
                    nms.push_back(ptr);
                }

                UINT cNames = UINT(nms.size());
                auto hr = pInterface->GetIDsOfNames( IID_NULL,(LPOLESTR *)nms.data(), cNames, lcid, result->data());
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

        
            Dispatch& Invoke( DISPID dispIdMember, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Invoke( dispIdMember, IID_NULL,lcid,wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };

        class SupportErrorInfo : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(SupportErrorInfo,Unknown,ISupportErrorInfo,IUnknown)

            bool InterfaceSupportsErrorInfo( REFIID riid)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->InterfaceSupportsErrorInfo(riid);
                if(hr == S_OK)
                {
                    return true;
                }
                else if(hr == S_FALSE)
                {
                    return false;
                }
                else if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return false;
            }
        };


        class ErrorInfo : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ErrorInfo,Unknown,IErrorInfo,IUnknown)


            static ErrorInfo GetErrorInfo()
            {
                HWIN_TRACE();
                IErrorInfo* pErrorInfo = nullptr;
                auto hr = ::GetErrorInfo(0,&pErrorInfo);
                if(hr == S_OK)
                {
                    return ErrorInfo(pErrorInfo);
                }
                return ErrorInfo();
            }

            GUID GetGUID( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                GUID result = {0,};
                auto hr = pInterface->GetGUID(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

            SysString GetSource( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                BSTR result = nullptr;
                auto hr = pInterface->GetSource(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return SysString(result,true);
            }
        
            SysString GetDescription( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                BSTR result = nullptr;
                auto hr = pInterface->GetDescription(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return SysString(result,true);
            }
        
            SysString GetHelpFile( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                BSTR result = nullptr;
                auto hr = pInterface->GetHelpFile(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return SysString(result,true);
            }

            DWORD GetHelpContext( DWORD *pdwHelpContext)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->GetHelpContext(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        };



        class CreateErrorInfo : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(CreateErrorInfo,Unknown,ICreateErrorInfo,IUnknown)

            CreateErrorInfo& SetGUID(REFGUID rguid)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetGUID(rguid);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            CreateErrorInfo& SetSource(LPOLESTR szSource)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetSource(szSource);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            CreateErrorInfo& SetDescription( LPOLESTR szDescription)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetDescription(szDescription);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            CreateErrorInfo& SetHelpFile( LPOLESTR szHelpFile)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetHelpFile(szHelpFile);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            CreateErrorInfo& SetHelpContext( DWORD dwHelpContext)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetHelpContext(dwHelpContext);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }


            static CreateErrorInfo Create()
            {
                HWIN_TRACE();
                ICreateErrorInfo* pCreateErrorInfo = nullptr;
                auto hr = ::CreateErrorInfo(&pCreateErrorInfo);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return CreateErrorInfo(pCreateErrorInfo);
            }


            static void SetErrorInfo(REFGUID rguid,LPOLESTR szSource,LPOLESTR szDescription = nullptr, LPOLESTR szHelpFile = nullptr, DWORD dwHelpContext = 0)
            {
                HWIN_TRACE();
                ICreateErrorInfo* pCreateErrorInfo = nullptr;
                auto hr = ::CreateErrorInfo(&pCreateErrorInfo);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                CreateErrorInfo cei(pCreateErrorInfo);
                cei.SetGUID(rguid);
                if(szSource)
                {
                    cei.SetSource(szSource);
                }
                if(szDescription)
                {
                    cei.SetDescription(szDescription);
                }
                if(szHelpFile)
                {
                    cei.SetHelpFile(szHelpFile);
                }
                cei.SetHelpContext(dwHelpContext);

                ErrorInfo ei = cei.As<ErrorInfo>();
                hr = ::SetErrorInfo(0,ei);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
            }




        };


        class ProvideClassInfo : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ProvideClassInfo,Unknown,IProvideClassInfo,IUnknown)

            TypeInfo GetClassInfo( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ITypeInfo *result = nullptr;
                auto hr = pInterface->GetClassInfo(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return TypeInfo(result);
            }


            GUID GetGUID( )
            {
                HWIN_TRACE();
                GUID result = {0,};

                auto pInterface = GetInterface();

                IProvideClassInfo2* pProvideClassInfo2 = nullptr;
                auto hr = pInterface->QueryInterface(&pProvideClassInfo2);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                UnknownPtr<IProvideClassInfo2> provideClassInfo2(pProvideClassInfo2);
                hr = pProvideClassInfo2->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

        };

        class OleAdviseHolder : public Unknown
        {
            
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(OleAdviseHolder,Unknown,IOleAdviseHolder,IUnknown)


            static OleAdviseHolder Create()
            {
                HWIN_TRACE();
                IOleAdviseHolder* result = nullptr;

                auto hr = CreateOleAdviseHolder(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return OleAdviseHolder(result);
            }

            DWORD Advise( IAdviseSink *pAdvise )
            {
                HWIN_TRACE();
                DWORD result = 0;

                auto pInterface = GetInterface();

                auto hr = pInterface->Advise(pAdvise,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            OleAdviseHolder& Unadvise(DWORD dwConnection)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->Unadvise(dwConnection);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumSTATDATA EnumAdvise()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumSTATDATA* result = nullptr;

                auto hr = pInterface->EnumAdvise(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumSTATDATA(result);
            }

            OleAdviseHolder& SendOnRename( IMoniker *pmk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->SendOnRename(pmk);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
            OleAdviseHolder& SendOnSave( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->SendOnSave( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            OleAdviseHolder& SendOnClose( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->SendOnClose( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

        };


        class OleCache : public Unknown
        {
            
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(OleCache,Unknown,IOleCache,IUnknown)


            static OleCache Create(REFIID refIID = __uuidof(IOleCache), LPUNKNOWN pUnkOuter = nullptr ,REFCLSID rclsid = CLSID_NULL)
            {
                HWIN_TRACE();
                IOleCache* pResult = nullptr;
                auto hr = CreateDataCache(pUnkOuter,rclsid,refIID,(LPVOID*)&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return OleCache(pResult);
            }

            DWORD Cache( FORMATETC *pformatetc, DWORD advf)
            {
                HWIN_TRACE();
                DWORD result = 0;

                auto pInterface = GetInterface();

                auto hr = pInterface->Cache(pformatetc, advf,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

            OleCache& Uncache( DWORD dwConnection)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->Uncache( dwConnection);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        

            EnumSTATDATA EnumCache()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumSTATDATA* result = nullptr;

                auto hr = pInterface->EnumCache(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumSTATDATA(result);
            }

            
        
            OleCache& InitCache( IDataObject *pDataObject )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->InitCache( pDataObject );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            OleCache& SetData( FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->SetData( pformatetc, pmedium, fRelease);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };


        class OleCache2 : public OleCache
        {
            
        public:
            typedef OleCache Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(OleCache2,OleCache,IOleCache2,IOleCache)


            static OleCache2 Create(REFIID refIID = __uuidof(IOleCache2), LPUNKNOWN pUnkOuter = nullptr ,REFCLSID rclsid = CLSID_NULL)
            {
                HWIN_TRACE();
                IOleCache2* pResult = nullptr;
                auto hr = CreateDataCache(pUnkOuter,rclsid,refIID,(LPVOID*)&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return OleCache2(pResult);
            }

            OleCache2& UpdateCache( LPDATAOBJECT pDataObject, DWORD grfUpdf)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->UpdateCache( pDataObject, grfUpdf,nullptr);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            OleCache2& DiscardCache( DWORD dwDiscardOptions)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->DiscardCache(dwDiscardOptions);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };


        class OleCacheControl : public Unknown
        {
            
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(OleCacheControl,Unknown,IOleCacheControl,IUnknown)

            OleCacheControl& OnRun( LPDATAOBJECT pDataObject)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->OnRun( pDataObject );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            OleCacheControl& OnStop( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->OnStop( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

        };


        class ParseDisplayName_ : public Unknown
        {
            
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ParseDisplayName_,Unknown,IParseDisplayName,IUnknown)

            Moniker ParseDisplayName( IBindCtx *pbc,LPOLESTR pszDisplayName, ULONG *pchEaten)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result = nullptr;

                auto hr = pInterface->ParseDisplayName( pbc,pszDisplayName, pchEaten,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }

        };


        class OleContainer : public ParseDisplayName_
        {
            
        public:
            typedef ParseDisplayName_ Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(OleContainer,ParseDisplayName_,IOleContainer,IParseDisplayName)

            EnumUnknown EnumObjects( DWORD grfFlags )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumUnknown* result = nullptr;

                auto hr = pInterface->EnumObjects( grfFlags,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumUnknown(result);
            }

            OleContainer& LockContainer( bool fLock)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                

                auto hr = pInterface->LockContainer(fLock?TRUE:FALSE);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

        };

        class OleClientSite : public Unknown
        {
            
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(OleClientSite,Unknown,IOleClientSite,IUnknown)

            OleClientSite& SaveObject( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->SaveObject( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            Moniker GetMoniker( DWORD dwAssign, DWORD dwWhichMoniker)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result = nullptr;

                auto hr = pInterface->GetMoniker( dwAssign, dwWhichMoniker,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }

            OleContainer GetContainer( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IOleContainer* result = nullptr;

                auto hr = pInterface->GetContainer(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return OleContainer(result);
            }
        
            OleClientSite& ShowObject( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->ShowObject( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            OleClientSite& OnShowWindow(bool fShow)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->OnShowWindow(fShow?TRUE:FALSE);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            OleClientSite& RequestNewObjectLayout( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();

                auto hr = pInterface->RequestNewObjectLayout();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };


        class EnumOLEVERB : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(EnumOLEVERB,Unknown,IEnumOLEVERB,IUnknown)

            bool Next( OLEVERB& theResult )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                ULONG actual = 0;
                auto hr = pInterface->Next(1,&theResult,&actual);
                if(actual)
                {
                    return true;
                }
                return false;
            }

            bool Next( ULONG requestedNumberOfElements, std::vector<OLEVERB>& result)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                result.clear();
                result.resize(requestedNumberOfElements);
                ULONG actual = 0;

                auto hr = pInterface->Next(1,result.data(),&actual);
                if(actual)
                {
                    if(result.size() != actual)
                    {
                        result.resize(actual);
                    }
                    return true;
                }
                return false;
            }

            EnumOLEVERB& Skip(ULONG numberOfElements)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Skip(numberOfElements);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumOLEVERB& Reset( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Reset();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumOLEVERB Clone()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumOLEVERB* pEnum = nullptr;
                auto hr = pInterface->Clone(&pEnum);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumOLEVERB(pEnum);
            }
        
        };




        class OleObject : public Unknown
        {
            
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(OleObject,Unknown,IOleObject,IUnknown)

            OleObject& SetClientSite( IOleClientSite *pClientSite)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetClientSite( pClientSite);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            OleClientSite GetClientSite( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IOleClientSite* result = nullptr;
                auto hr = pInterface->GetClientSite(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return OleClientSite(result);
            }
        
            OleObject& SetHostNames( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetHostNames( szContainerApp, szContainerObj);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            OleObject& Close( DWORD dwSaveOption)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Close(dwSaveOption);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            OleObject& SetMoniker( DWORD dwWhichMoniker, IMoniker *pmk)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetMoniker( dwWhichMoniker, pmk);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            Moniker GetMoniker( DWORD dwAssign, DWORD dwWhichMoniker )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IMoniker* result = nullptr;
                auto hr = pInterface->GetMoniker( dwAssign, dwWhichMoniker,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return Moniker(result);
            }
        
            OleObject& InitFromData( IDataObject *pDataObject, bool fCreation)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->InitFromData( pDataObject, fCreation,0);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            DataObject GetClipboardData( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IDataObject* result = nullptr;
                auto hr = pInterface->GetClipboardData(0,&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return DataObject(result);
            }
        
            OleObject& DoVerb( LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite, LONG lindex,HWND hwndParent, LPCRECT lprcPosRect)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->DoVerb( iVerb, lpmsg, pActiveSite, lindex,hwndParent, lprcPosRect);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumOLEVERB EnumVerbs( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumOLEVERB* result = nullptr;
                auto hr = pInterface->EnumVerbs(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumOLEVERB(result);
            }
        
            OleObject& Update( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Update( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            bool IsUpToDate( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->IsUpToDate( );
                if(hr == S_OK)
                {
                    return true;
                }
                else if (hr == S_FALSE)
                {
                    return false;
                }

                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return false;
            }
        
            CLSID GetUserClassID( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                CLSID result = {0,};
                auto hr = pInterface->GetUserClassID( &result );
                

                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            String GetUserType( DWORD dwFormOfType )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                LPOLESTR result = nullptr;
                auto hr = pInterface->GetUserType(dwFormOfType, &result );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                Malloc malloc = Malloc::GetMalloc();
                String s(result);
                malloc.Free(result);
                return s;
            }
        
            OleObject& SetExtent( DWORD dwDrawAspect, SIZEL *psizel)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetExtent( dwDrawAspect, psizel);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            SIZEL GetExtent( DWORD dwDrawAspect)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                SIZEL result = {0,};
                auto hr = pInterface->GetExtent( dwDrawAspect, &result );

                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            DWORD Advise( IAdviseSink *pAdvSink)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->Advise( pAdvSink, &result );

                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            OleObject& Unadvise( DWORD dwConnection)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Unadvise( dwConnection );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumSTATDATA EnumAdvise( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumSTATDATA* result = nullptr;
                auto hr = pInterface->EnumAdvise(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumSTATDATA(result);
            }

            DWORD GetMiscStatus( DWORD dwAspect)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->GetMiscStatus( dwAspect,&result );

                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            OleObject& SetColorScheme(LOGPALETTE *pLogpal)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetColorScheme(pLogpal);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        };


        class OleWindow : public Unknown
        {
            
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(OleWindow,Unknown,IOleWindow,IUnknown)

            HWND GetWindow( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                HWND result = 0;
                auto hr = pInterface->GetWindow( &result );

                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            OleWindow& ContextSensitiveHelp( bool fEnterMode)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ContextSensitiveHelp(fEnterMode);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

        };


        class ConnectData
        {
        public:
        private:
            struct Data : CONNECTDATA
            {
                long referenceCount; 
                Data()
                    : referenceCount(1)
                {
                    pUnk = nullptr;
                    dwCookie = 0;
                }

                Data(const CONNECTDATA& other, bool addref = false)
                    : referenceCount(1)
                {
                    pUnk = other.pUnk;
                    dwCookie = other.dwCookie;
                    if(pUnk && addref)
                    {
                        pUnk->AddRef();
                    }
                }

                Data(const CONNECTDATA* other, bool addref = false)
                    : referenceCount(1)
                {
                    if(other)
                    {
                        pUnk = other->pUnk;
                        dwCookie = other->dwCookie;
                        if(pUnk && addref)
                        {
                            pUnk->AddRef();
                        }
                    }
                    else
                    {
                        pUnk = nullptr;
                        dwCookie = 0;
                    }
                }

                ~Data()
                {
                    if(pUnk)
                    {
                        pUnk->Release();
                        pUnk = nullptr;
                    }
                }
            };
            Data* data;

            void Clear()
            {
                if(data)
                {
                    auto res = InterlockedDecrement( &data->referenceCount );
                    if(res == 0)
                    {
                        delete data;
                        data = 0;
                    }
                }
            }
        public:
            ConnectData()
                : data( )
            {}

            ConnectData(const CONNECTDATA& other, bool addref = false)
                : data(new Data(other,addref))
            {}

            ConnectData(const CONNECTDATA* other, bool addref = false)
                : data(new Data(other,addref))
            {}

            ConnectData(const ConnectData& other)
                : data(other.data)
            {
                if(data)
                {
                    InterlockedIncrement( &data->referenceCount );
                }
            }

            ConnectData(ConnectData&& other)
                : data(other.data)
            {
                other.data = nullptr;
            }

            ~ConnectData()
            {
                Clear();    
            }


            ConnectData& operator = (const ConnectData& other)
            {
                if(data != other.data)
                {
                    Clear();
                    data = other.data;
                    if(data)
                    {
                        InterlockedIncrement( &data->referenceCount );
                    }
                }
                return *this;
            }

            ConnectData& operator = (ConnectData&& other)
            {
                if(data != other.data)
                {
                    Clear();
                    data = other.data;
                    other.data = nullptr;
                }
                return *this;
            }

            operator bool () const
            {
                return data != nullptr;
            }


            const CONNECTDATA* Get() const
            {
                return data;
            }

            CONNECTDATA* Get()
            {
                if(!data)
                {
                    data = new Data();
                }
                return data;
            }

            IUnknown* Unknown() const
            {
                if(data)
                {
                    return data->pUnk;
                }
                return nullptr;
            }

            ConnectData& SetUnknown(IUnknown* pUnk, bool addref = false)
            {
                auto d = Get();
                d->pUnk = pUnk;
                if(pUnk && addref)
                {
                    pUnk->AddRef();
                }
                return *this;
            }

            DWORD Cookie() const
            {
                if(data)
                {
                    return data->dwCookie;
                }
                return 0;
            }

            ConnectData& SetCookie(DWORD cookie)
            {
                auto d = Get();
                d->dwCookie = cookie;
                return *this;
            }

            ConnectData& Set(DWORD cookie,IUnknown* pUnk, bool addref = false)
            {
                auto d = Get();
                d->dwCookie = cookie;
                d->pUnk = pUnk;
                if(pUnk && addref)
                {
                    pUnk->AddRef();
                }
                return *this;
            }

            ConnectData& Set(const CONNECTDATA& theCONNECTDATA , bool addref = false)
            {
                auto d = Get();
                d->dwCookie = theCONNECTDATA.dwCookie;
                d->pUnk = theCONNECTDATA.pUnk;
                if(d->pUnk && addref)
                {
                    d->pUnk->AddRef();
                }
                return *this;
            }

            HRESULT AssignTo(CONNECTDATA& theCONNECTDATA) const
            {
                HRESULT result = S_OK;
                if(theCONNECTDATA.pUnk)
                {
                    theCONNECTDATA.pUnk->Release();
                    theCONNECTDATA.pUnk = nullptr;
                }
                theCONNECTDATA.dwCookie = 0;
                auto d = Get();
                if(d)
                {
                    theCONNECTDATA.dwCookie = d->dwCookie;
                    theCONNECTDATA.pUnk = d->pUnk;
                    theCONNECTDATA.pUnk->AddRef();
                }
                return result;
            }



        };

        class EnumConnections : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(EnumConnections,Unknown,IEnumConnections,IUnknown)

            bool Next( ConnectData& theResult )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                CONNECTDATA element = {0,};
                ULONG actual = 0;
                auto hr = pInterface->Next(1,&element,&actual);
                if(actual)
                {
                    theResult.Set(element);
                    return true;
                }
                return false;
            }
            bool Next( ULONG requestedNumberOfElements, std::vector<ConnectData>& result)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                CONNECTDATA* elements = (CONNECTDATA*)alloca(requestedNumberOfElements*sizeof(CONNECTDATA));
                memset(elements,0,requestedNumberOfElements*sizeof(CONNECTDATA));
                ULONG actual = 0;

                auto hr = pInterface->Next(1,elements,&actual);
                if(actual)
                {
                    result.clear();
                    for(ULONG i= 0; i < actual; i++)
                    {
                        result.push_back(ConnectData(elements[i]));
                    }
                    return true;
                }
                return false;
            }
            EnumConnections& Skip(ULONG numberOfElements)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Skip(numberOfElements);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumConnections& Reset( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Reset();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumConnections Clone()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumConnections* pClone = nullptr;
                auto hr = pInterface->Clone(&pClone);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumConnections(pClone);
            }

        };

        class ConnectionPointContainer;
        class ConnectionPoint : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ConnectionPoint,Unknown,IConnectionPoint,IUnknown)

            IID GetConnectionInterface( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IID result = {0,};
                auto hr = pInterface->GetConnectionInterface(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }

            ConnectionPointContainer GetConnectionPointContainer( );
        
            DWORD Advise( IUnknown *pUnkSink )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->Advise(pUnkSink, &result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            ConnectionPoint& Unadvise(DWORD dwCookie)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Unadvise(dwCookie);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumConnections EnumConnections( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumConnections* pEnum = nullptr;
                auto hr = pInterface->EnumConnections(&pEnum);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return harlinn::windows::EnumConnections(pEnum);
            }

        };



        class EnumConnectionPoints : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(EnumConnectionPoints,Unknown,IEnumConnectionPoints,IUnknown)

            bool Next( ConnectionPoint& theResult )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IConnectionPoint* pElement = nullptr;
                ULONG actual = 0;
                auto hr = pInterface->Next(1,&pElement,&actual);
                if(actual)
                {
                    theResult.Reset(pElement);
                    return true;
                }
                return false;
            }
            bool Next( ULONG requestedNumberOfElements, std::vector<ConnectionPoint>& result)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IConnectionPoint** pElements = (IConnectionPoint**)alloca(requestedNumberOfElements*sizeof(IConnectionPoint*));
                memset(pElements,0,requestedNumberOfElements*sizeof(IConnectionPoint*));
                ULONG actual = 0;

                auto hr = pInterface->Next(1,pElements,&actual);
                if(actual)
                {
                    result.clear();
                    for(ULONG i= 0; i < actual; i++)
                    {
                        result.push_back(ConnectionPoint(pElements[i]));
                    }
                    return true;
                }
                return false;
            }
            EnumConnectionPoints& Skip(ULONG numberOfElements)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Skip(numberOfElements);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            EnumConnectionPoints& Reset( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Reset();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            EnumConnectionPoints Clone()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumConnectionPoints* pClone = nullptr;
                auto hr = pInterface->Clone(&pClone);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return EnumConnectionPoints(pClone);
            }

        };

        class ConnectionPointContainer : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ConnectionPointContainer,Unknown,IConnectionPointContainer,IUnknown)

            EnumConnectionPoints EnumConnectionPoints()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IEnumConnectionPoints* pResult = nullptr;
                auto hr = pInterface->EnumConnectionPoints(&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return harlinn::windows::EnumConnectionPoints(pResult);
            }
        
            ConnectionPoint FindConnectionPoint( REFIID riid)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IConnectionPoint* pResult = nullptr;
                auto hr = pInterface->FindConnectionPoint(riid, &pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return ConnectionPoint(pResult);
            }

        };

        inline ConnectionPointContainer ConnectionPoint::GetConnectionPointContainer( )
        {
            HWIN_TRACE();
            auto pInterface = GetInterface();
            IConnectionPointContainer* pResult = nullptr;
            auto hr = pInterface->GetConnectionPointContainer(&pResult);
            if(FAILED(hr))
            {
                CheckHRESULT(hr);
            }
            return ConnectionPointContainer(pResult);
        }



    }
};

#endif // __HWINOBJ_H__